package fun.tan90.device.sink.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import fun.tan90.device.event.EventTopic;
import fun.tan90.device.event.model.DeviceTransferData;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.noear.dami.Dami;
import org.noear.snack.ONode;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.bean.LifecycleBean;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Getter
public abstract class SinkHandler implements LifecycleBean {

    private static final String SINK_RULE_KEY = "{}_{}";

    public static final Map<String, List<? extends SinkRule>> SINK_RULES = new HashMap<>();

    @Inject("${plugin-name}")
    String pluginName;

    @Inject
    AppContext appContext;

    public abstract void init(List<ONode> onodeList);

    @Override
    public void start() {
        ONode root = Dami.<String, ONode>bus().sendAndRequest(EventTopic.SINK_RULE_TOPIC, pluginName);
        log.info("SinkRule {}", root.toJson());
        init(root.ary());
    }

    public abstract void handle(Map<String, Object> data, Map<String, String> meta, List<? extends SinkRule> sinkRules);

    @Override
    public void postStart() throws Throwable {
        Dami.<DeviceTransferData, Void>bus().listen(EventTopic.DEVICE_TRANSFER_DATA_TOPIC, data -> {
            DeviceTransferData deviceTransferData = data.getContent();
            log.info("topic: {}, data: {}", data.getTopic(), deviceTransferData);
            List<? extends SinkRule> sinkRules = SINK_RULES.get(sinkRuleKey(deviceTransferData.getDeviceType(), deviceTransferData.getDataSource()));
            if (CollUtil.isEmpty(sinkRules)) {
                log.warn("暂无sink_rule {}", deviceTransferData);
                return;
            }
            Map<String, String> meta = Map.of("deviceType", deviceTransferData.getDeviceType(), "dataSource", deviceTransferData.getDataSource(), "deviceCode", deviceTransferData.getDeviceCode());
            handle(deviceTransferData.getData(), meta, sinkRules);
        });
    }


    public String sinkRuleKey(String deviceType, String dataSource) {
        return StrUtil.format(SINK_RULE_KEY, deviceType, dataSource);
    }
}
